package com.ruicar.afs.cloud.afscase.risk.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ruicar.afs.cloud.afscase.approveprev.entity.CaseApprovePrevInfo;
import com.ruicar.afs.cloud.afscase.common.utils.Const;
import com.ruicar.afs.cloud.afscase.infomanagement.entity.CaseBaseInfo;
import com.ruicar.afs.cloud.afscase.infomanagement.entity.CaseCarInfo;
import com.ruicar.afs.cloud.afscase.infomanagement.service.CaseBaseInfoService;
import com.ruicar.afs.cloud.afscase.paramconfmanagement.service.CaseConfParamService;
import com.ruicar.afs.cloud.afscase.infomanagement.service.CaseCarInfoService;
import com.ruicar.afs.cloud.afscase.risk.config.TortoiseLinkConfig;
import com.ruicar.afs.cloud.afscase.risk.config.VehicleSystemConfig;
import com.ruicar.afs.cloud.afscase.risk.entity.*;
import com.ruicar.afs.cloud.afscase.risk.service.*;
import com.ruicar.afs.cloud.common.core.enums.AfsEnumUtil;
import com.ruicar.afs.cloud.common.core.exception.AfsBaseException;
import com.ruicar.afs.cloud.common.core.holder.TransRequestContextHolder;
import com.ruicar.afs.cloud.common.core.security.util.SecurityUtils;
import com.ruicar.afs.cloud.common.modules.afscorebusiness.enums.BusinessStateInEnum;
import com.ruicar.afs.cloud.common.modules.afscorebusiness.enums.BusinessTypeEnum;
import com.ruicar.afs.cloud.common.modules.afscorebusiness.enums.TortoiseApplyExecuteEnum;
import com.ruicar.afs.cloud.common.modules.afscorebusiness.enums.WhetherEnum;
import com.ruicar.afs.cloud.image.config.FileProperties;
import com.ruicar.afs.cloud.image.entity.ComAttachmentManagement;
import com.ruicar.afs.cloud.image.enums.AttachmentUniqueCodeEnum;
import com.ruicar.afs.cloud.image.service.ComAttaManageService;
import com.ruicar.afs.cloud.image.service.ComAttachmentFileService;
import com.ruicar.afs.cloud.image.vo.UploadInputVo;
import com.ruicar.afs.cloud.risk.api.dto.tortoise.request.TortoiseApplyData;
import com.ruicar.afs.cloud.risk.api.dto.tortoise.request.TortoiseFraudPushData;
import com.ruicar.afs.cloud.risk.api.dto.tortoise.request.TortoisePrevApproveData;
import com.ruicar.afs.cloud.risk.api.enums.tortoise.GwtTortoiseAntiFraudCallStep;
import com.ruicar.afs.cloud.risk.api.enums.tortoise.GwtTortoiseFlowType;
import com.ruicar.afs.cloud.risk.api.enums.tortoise.GwtTortoiseFraudPushResult;
import com.ruicar.afs.cloud.risk.api.enums.tortoise.GwtTortoiseStartApproveType;
import com.ruicar.afs.cloud.risk.api.service.AfsRiskControlService;
import com.ruicar.afs.cloud.vehicle.dto.CarInfoDto;
import com.ruicar.afs.cloud.vehicle.feign.VehicleApiFeign;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.io.File;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Description
 * @Author Peng Jinbo
 * @Date 2020/07/24 14:52
 */
@Service
@AllArgsConstructor
@Slf4j
public class CaseTortoiseServiceImpl implements CaseTortoiseService {
    /**
     * Data query service
     */
    private DataQueryService dataQueryService;
    /**
     * Risk control service
     */
    private AfsRiskControlService riskControlService;

    /**
     * Case tortoise prev service
     */
    private CaseTortoisePrevService caseTortoisePrevService;
    /**
     * Case tortoise fraud push service
     */
    private CaseTortoiseFraudPushService caseTortoiseFraudPushService;
    /**
     * Case tortoise decision hand service
     */
    private CaseTortoiseDecisionHandService caseTortoiseDecisionHandService;
    /**
     * Case tortoise apply service
     */
    private CaseTortoiseApplyService caseTortoiseApplyService;
    /**
     * Case tortoise fraud hand service
     */
    private CaseTortoiseFraudHandService caseTortoiseFraudHandService;

    private CaseBaseInfoService caseBaseInfoService;

    private CaseConfParamService caseConfParamService;

    private TortoiseLinkConfig tortoiseLinkConfig;

    private ComAttachmentFileService comAttachmentFileService;

    private ComAttaManageService comAttaManageService;

    private FileProperties fileProperties;

    private VehicleApiFeign vehicleApiFeign;

    private CaseCarInfoService caseCarInfoService;

    private VehicleSystemConfig vehicleSystemConfig;


    /**
     * Author Peng Jinbo
     * Signal apply *
     *
     * @param applyNo apply no
     */
    @Override
    @Transactional
    public void signalApply(String applyNo,boolean isHandInvoke,GwtTortoiseStartApproveType startApproveType){
        startApproveType = Objects.isNull(startApproveType) ? GwtTortoiseStartApproveType.NORMAL : startApproveType;
        CaseTortoiseApply apply = new CaseTortoiseApply();
        apply.setApplyNo(applyNo);
        apply.setOperateDate(new Date());
        apply.setHandInvoke(isHandInvoke ? WhetherEnum.YES.getCode() : WhetherEnum.NO.getCode());
        apply.setType(AfsEnumUtil.key(startApproveType));
        caseTortoiseApplyService.save(apply);
        TortoiseApplyData businessData = dataQueryService.getApplyData(applyNo);
        businessData.setApproveType(startApproveType);
        businessData.setSerialNumber(apply.getId().toString());
        businessData.setCallStep(GwtTortoiseAntiFraudCallStep.NORMAL_APPLY);
        log.info("发送玄武进单[正式进件]信号 START... SerialNumber: {}",businessData.getSerialNumber());
        String trackId = riskControlService.signalApply(businessData);
        log.info("发送玄武进单[正式进件]信号 END... SerialNumber: {}",businessData.getSerialNumber());

        caseBaseInfoService.update(
                Wrappers.<CaseBaseInfo>lambdaUpdate()
                        .eq(CaseBaseInfo::getApplyNo,applyNo)
                        .set(CaseBaseInfo::getTortoiseApplyExecute,AfsEnumUtil.key(TortoiseApplyExecuteEnum.PROCESSING))
                        // 人工调用时不改变案件状态
                        .set(! isHandInvoke,CaseBaseInfo::getBusinessStateIn,AfsEnumUtil.key(BusinessStateInEnum.WAIT_QUERY))
        );
    }

    @Override
    public void signalApply(String applyNo,GwtTortoiseStartApproveType startApproveType) {
        signalApply(applyNo,false,startApproveType);
    }
    /**
     * Author Peng Jinbo
     * Signal prev *
     *
     * @param prevInfo prev info
     */
    @Override
    @Transactional
    public void signalPrev(CaseApprovePrevInfo prevInfo){
        TortoisePrevApproveData prevApproveData = dataQueryService.queryPrev(prevInfo);
        BusinessTypeEnum businessTypeEnum = (BusinessTypeEnum) AfsEnumUtil.getEnum(prevInfo.getBusinessType(),BusinessTypeEnum.class);
        Assert.notNull(businessTypeEnum,"预审批业务类型不可为空.");
        GwtTortoiseFlowType prevType;
        if(businessTypeEnum == BusinessTypeEnum.NEW_CAR) {
            prevType = GwtTortoiseFlowType.PREV_APPROVE;
        } else {
            prevType = GwtTortoiseFlowType.OLD_CAR_PREV_EXTEND;
        }
        CaseTortoisePrev prev = new CaseTortoisePrev();
        prev.setApplyNo(prevApproveData.getApplyNo());
        prev.setOperateDate(new Date());
        prev.setPrevId(prevInfo.getId().toString());
        prev.setApplyNo(prevInfo.getApplyNo());
        prev.setType(prevType);
        caseTortoisePrevService.save(prev);
        prevApproveData.setSerialNumber(prev.getId().toString());
        prevApproveData.setApplyNo(prev.getApplyNo());
        log.info("发送玄武进单[预审批]信号 START... SerialNumber: {}",prevApproveData.getSerialNumber());
        String trackId = riskControlService.signalPrevApprove(prevApproveData);
        log.info("发送玄武进单[预审批]信号 END... SerialNumber: {}",prevApproveData.getSerialNumber());
    }

    /**
     * Author Peng Jinbo
     * Signal fraud push *
     *
     * @param fraudPushData     fraud push data
     * @param antiFraudCallStep anti fraud call step
     */
    @Override
    @Transactional
    public void signalFraudPush(TortoiseFraudPushData fraudPushData, GwtTortoiseAntiFraudCallStep antiFraudCallStep){
        beforeSignalCheck(fraudPushData.getApplyNo());
        CaseTortoiseFraudPush fraudPush = new CaseTortoiseFraudPush();
        fraudPush.setApplyNo(fraudPushData.getApplyNo());
        fraudPush.setOperateDate(new Date());
        fraudPush.setOperateStaff(SecurityUtils.getUsername());
        fraudPush.setFraudType(fraudPushData.getFraudType());
        fraudPush.setDealerJoin(fraudPushData.getDealerJoin());
        fraudPush.setDetailMessage(fraudPushData.getFraudDetailMessage());
        fraudPush.setCallStep(antiFraudCallStep);
        fraudPush.setOperateStaffName(SecurityUtils.getUser().getUserRealName());
        // 默认推送成功
        fraudPush.setPushResult(AfsEnumUtil.desc(GwtTortoiseFraudPushResult.PUSHED));
        caseTortoiseFraudPushService.save(fraudPush);


        fraudPushData.setCallStep(antiFraudCallStep);
        fraudPushData.setSerialNumber(fraudPush.getId().toString());
        log.info("发送玄武进单[欺诈信息推送]信号 START... SerialNumber: {}",fraudPushData.getSerialNumber());
        String trackId = riskControlService.signalFraudPush(fraudPushData);
        log.info("发送玄武进单[欺诈信息推送]信号 END... SerialNumber: {}",fraudPushData.getSerialNumber());
    }

    /**
     * @Description 只推送最新数据
     * @Author Peng_Jinbo
     * @Date 2020/9/8 13:04
     */
    @Override
    public void signalFraudPush(String applyNo){
        signalFraudPush(applyNo,GwtTortoiseStartApproveType.NORMAL);
    }

    /**
    * @Description 只推送最新数据
    * @Author Peng_Jinbo
    * @Date 2020/9/8 13:04
    */
    @Override
    public void signalFraudPush(String applyNo,GwtTortoiseStartApproveType startApproveType) {
        beforeSignalCheck(applyNo);
        startApproveType = Objects.isNull(startApproveType) ? GwtTortoiseStartApproveType.NORMAL : startApproveType;
        Optional<CaseTortoiseFraudPush> optional = caseTortoiseFraudPushService.list(
                Wrappers.<CaseTortoiseFraudPush>lambdaQuery()
                        .eq(CaseTortoiseFraudPush::getApplyNo, applyNo)
                        .orderByDesc(CaseTortoiseFraudPush::getCreateTime)
        ).stream().findFirst();

        if(optional.isPresent()){
            CaseBaseInfo baseInfo = caseBaseInfoService.getOne(
                    Wrappers.<CaseBaseInfo>lambdaQuery()
                            .eq(CaseBaseInfo::getApplyNo, applyNo)
            );
            CaseTortoiseFraudPush fraudPush = optional.get();
            if(!AfsEnumUtil.desc(GwtTortoiseFraudPushResult.PUSHED).equals(fraudPush.getPushResult())) {

                TortoiseFraudPushData pushData = TortoiseFraudPushData.builder()
                        .dealerJoin(fraudPush.getDealerJoin())
                        .fraudType(fraudPush.getFraudType())
                        .fraudDetailMessage(fraudPush.getDetailMessage())
                        .pushUser(fraudPush.getOperateStaffName())
                        .build();

                pushData.setCallStep(fraudPush.getCallStep());
                pushData.setSerialNumber(fraudPush.getId().toString());
                pushData.setApplyNo(fraudPush.getApplyNo());
                pushData.setMainId(baseInfo.getId().toString());
                pushData.setApproveType(startApproveType);
                log.info("发送玄武进单[欺诈信息推送]信号 START... SerialNumber: {}", pushData.getSerialNumber());
                String trackId = riskControlService.signalFraudPush(pushData);
                log.info("发送玄武进单[欺诈信息推送]信号 END... SerialNumber: {}", pushData.getSerialNumber());
                fraudPush.setPushResult(AfsEnumUtil.desc(GwtTortoiseFraudPushResult.PUSHED));
                caseTortoiseFraudPushService.updateById(fraudPush);
            }
        }
    }

    /**
     * Author Peng Jinbo
     * Signal fraud hand *
     *
     * @param applyNo           apply no
     * @param antiFraudCallStep anti fraud call step
     */
    @Override
    @Transactional
    public void signalFraudHand(String applyNo, GwtTortoiseAntiFraudCallStep antiFraudCallStep, GwtTortoiseStartApproveType startApproveType){
        beforeSignalCheck(applyNo);
        CaseTortoiseFraudHand fraudHand = new CaseTortoiseFraudHand();
        fraudHand.setApplyNo(applyNo);
        fraudHand.setOperateDate(new Date());
        fraudHand.setCallStep(antiFraudCallStep);
        caseTortoiseFraudHandService.save(fraudHand);

        TortoiseApplyData applyData = dataQueryService.getApplyData(applyNo);
        applyData.setApproveType(startApproveType);
        applyData.setCallStep(antiFraudCallStep);
        applyData.setSerialNumber(fraudHand.getId().toString());
        log.info("发送玄武进单[反欺诈手动调用]信号 START... SerialNumber: {}",applyData.getSerialNumber());
        String trackId = riskControlService.signalFraudHandInvoke(applyData);
        log.info("发送玄武进单[反欺诈手动调用]信号 END... SerialNumber: {}",applyData.getSerialNumber());
    }

    @Override
    public void signalFraudHand(String applyNo, GwtTortoiseAntiFraudCallStep callStep){
        signalFraudHand(applyNo,callStep,GwtTortoiseStartApproveType.NORMAL);
    }

    @Override
    public void safeSignalFraudHand(String applyNo, GwtTortoiseAntiFraudCallStep callStep,GwtTortoiseStartApproveType startApproveType){
        try{
            log.info("玄武发欺诈调用触发：applyNo:{},callStep:{}",applyNo,callStep);
            if (caseConfParamService.checkSwitch(Const.PARAMS_SWITCH_XUANWU)) {
                signalFraudHand(applyNo, callStep,startApproveType);
            }else{
                log.info("玄武开关关闭，反欺诈触发调用取消 applyNo: {}, callStep: {}",applyNo,callStep);
            }
        }catch (Exception e){
            log.error(String.format("反欺诈触发调用失败，applyNo: %s,callStep: %s",applyNo,callStep.name()),e);
        }
    }

    @Override
    public void safeSignalFraudHand(String applyNo, GwtTortoiseAntiFraudCallStep callStep){
        this.safeSignalFraudHand(applyNo,callStep,GwtTortoiseStartApproveType.NORMAL);
    }

    /**
    * @Description 延迟1秒调用 080场景
    * @Author Peng_Jinbo
    * @Date 2020/9/17 16:48
    */
    @Override
    public void safeDelaySignFraudHand(final String applyNo,final GwtTortoiseAntiFraudCallStep callStep,final GwtTortoiseStartApproveType startApproveType){
        ThreadUtil.execute(()->{
            ThreadUtil.sleep(1000);
            TransRequestContextHolder.clear();
            this.safeSignalFraudHand(applyNo,callStep,startApproveType);
        });
    }


    @Override
    public void safeDelaySignFraudHand(final String applyNo,final GwtTortoiseAntiFraudCallStep callStep){
        this.safeDelaySignFraudHand(applyNo,callStep,GwtTortoiseStartApproveType.NORMAL);
    }

    /**
     * Author Peng Jinbo
     * Signal decision hand *
     *
     * @param applyNo apply no
     */
    @Override
    @Transactional
    public void signalDecisionHand(String applyNo){
        beforeSignalCheck(applyNo);
        CaseTortoiseDecisionHand decisionHand = new CaseTortoiseDecisionHand();
        decisionHand.setApplyNo(applyNo);
        decisionHand.setOperateDate(new Date());
        caseTortoiseDecisionHandService.save(decisionHand);

        TortoiseApplyData applyData = dataQueryService.getApplyData(applyNo);
        applyData.setSerialNumber(decisionHand.getId().toString());
        log.info("发送玄武进单[决策引擎手动调用]信号 END... SerialNumber: {}",applyData.getSerialNumber());
        String trackId = riskControlService.signalDecisionHandInvoke(applyData);
        log.info("发送玄武进单[决策引擎手动调用]信号 END... SerialNumber: {}",applyData.getSerialNumber());
    }

    /**
     * Author Peng Jinbo
     * Before sign check *
     *
     * @param applyNo apply no
     */
    @Override
    public void beforeSignalCheck(String applyNo) {
        Assert.isTrue(StrUtil.isNotBlank(applyNo),"申请编号不可为空");
        List<CaseTortoiseApply> tortoiseApplyRecordList = caseTortoiseApplyService.list(
                Wrappers.<CaseTortoiseApply>lambdaQuery()
                    .eq(CaseTortoiseApply::getApplyNo,applyNo)
                    .isNotNull(CaseTortoiseApply::getNoticeDate)
        );
        Assert.isTrue(CollectionUtil.isNotEmpty(tortoiseApplyRecordList),"操作失败，未获取到[ 正式进件 ]成功调用记录");
    }
    /**
     * fangchenliang
     * 同盾报告下载
     */
    @Override
    public void downloadTdReport(String applyNo){
        CaseBaseInfo caseBaseInfo = caseBaseInfoService.getOne(Wrappers.<CaseBaseInfo>lambdaQuery().eq(CaseBaseInfo::getApplyNo,applyNo));
        String url=tortoiseLinkConfig.getTongdunReportUrl();
        String path=fileProperties.getTempDir();
        String applicationno=Convert.toStr(caseBaseInfo.getId());
        String getUrl=url + "?applicationno="+applicationno;
        try {
            HttpResponse httpResponse = HttpUtil.createGet(getUrl).execute();
            if(httpResponse.getStatus()!=200){
                throw  new AfsBaseException("访问同盾报告地址失败！"+"地址："+getUrl+"返回报文："+httpResponse.toString());
            }
            String filePath=path+File.separator+"tdReport-"+applyNo+".pdf";
            File file= FileUtil.writeBytes(httpResponse.bodyBytes(),filePath);
            ComAttachmentManagement comAttachmentManagement= comAttaManageService.getOne(Wrappers.<ComAttachmentManagement>lambdaQuery()
                    .eq(ComAttachmentManagement::getUniqueCode, AttachmentUniqueCodeEnum.TONGDUN_REPORT.getCode()));
            UploadInputVo uploadInputVo=new UploadInputVo();
            uploadInputVo.setBusiNo(applyNo);
            uploadInputVo.setBelongNo(applyNo);
            uploadInputVo.setAttachmentId(Convert.toStr(comAttachmentManagement.getId()));
            uploadInputVo.setArchiveClass(comAttachmentManagement.getArchiveClass());
            uploadInputVo.setAttachmentName(comAttachmentManagement.getAttachmentName());
            uploadInputVo.setFileType("pdf");
            uploadInputVo.setFileName(file.getName());
            uploadInputVo.setFileSource("com_attachment_management");
            uploadInputVo.setFileVersion("0");
            comAttachmentFileService.storeFileToOss(file,uploadInputVo);
            log.info("{}同盾报告下载成功!",applyNo);
            FileUtil.del(file);
        }catch (Exception e){
            log.warn("{}同盾报告下载下载失败:{}",applyNo,e);
        }
    }

    /**
     * add by fangchenliang
     * 车e估车辆评估报告
     */
    public void downloadECarReport(String applyNo){
        String url=vehicleSystemConfig.getUrl();
        List<CaseCarInfo> carInfoList=caseCarInfoService.list(Wrappers.<CaseCarInfo>lambdaQuery().eq(CaseCarInfo::getApplyNo,applyNo));
        if(!CollectionUtils.isEmpty(carInfoList)) {
            for (CaseCarInfo carInfo : carInfoList) {
                String vin=carInfo.getCarVin();
                String version=carInfo.getVersion();
                if (!StringUtils.isEmpty(vin)&&!StringUtils.isEmpty(version)) {
                    try {
                        HttpResponse httpResponse = HttpUtil.createGet(url+"/vinpgbg/downloadPgbgPdf?vin="+vin+"&version="+version).execute();
                        if(httpResponse.getStatus()!=200){
                            throw new AfsBaseException("访问车e估车辆评估报告地址失败！");
                        }
                        String filePath=fileProperties.getTempDir()+File.separator+"eCarReport-"+applyNo+".pdf";
                        File file= FileUtil.writeBytes(httpResponse.bodyBytes(),filePath);
                        ComAttachmentManagement comAttachmentManagement= comAttaManageService.getOne(Wrappers.<ComAttachmentManagement>lambdaQuery()
                                .eq(ComAttachmentManagement::getUniqueCode, AttachmentUniqueCodeEnum.ECAR_ASSESS_REPORT.getCode()));
                        UploadInputVo uploadInputVo=new UploadInputVo();
                        uploadInputVo.setBusiNo(applyNo);
                        uploadInputVo.setBelongNo(applyNo);
                        uploadInputVo.setAttachmentId(Convert.toStr(comAttachmentManagement.getId()));
                        uploadInputVo.setArchiveClass(comAttachmentManagement.getArchiveClass());
                        uploadInputVo.setAttachmentName(comAttachmentManagement.getAttachmentName());
                        uploadInputVo.setFileType("pdf");
                        uploadInputVo.setFileName(file.getName());
                        uploadInputVo.setFileSource("com_attachment_management");
                        uploadInputVo.setFileVersion("0");
                        comAttachmentFileService.storeFileToOss(file,uploadInputVo);
                        log.info("{}车e估车辆评估报告下载成功",applyNo);
                        FileUtil.del(file);
                    }catch (Exception e){
                        log.warn("{}车e估车辆评估报告下载失败:{}",applyNo,e);
                    }
                }else{
                    log.warn("{}车e估车辆评估报告下载失败:vin号或者版本号为空{}{}",applyNo,vin,version);
                }
            }

        }
    }

    @Override
    public void downloadPictureByUrl(String id,String carId,String imgUrl,String remake) {
        String path=fileProperties.getTempDir();
        try {
            HttpResponse httpResponse = HttpUtil.createGet(imgUrl).execute();
            if(httpResponse.getStatus()!=200){
                throw  new AfsBaseException("访问GPS安装图片失败！");
            }
            String filePath=path+File.separator+"tdReport-"+carId+".jpg";
            File file= FileUtil.writeBytes(httpResponse.bodyBytes(),filePath);

            UploadInputVo uploadInputVo=new UploadInputVo();
            uploadInputVo.setBusiNo(id);
            uploadInputVo.setBelongNo(carId);
            uploadInputVo.setAttachmentId(null);
            uploadInputVo.setArchiveClass(null);
            uploadInputVo.setAttachmentName(remake);
            uploadInputVo.setFileType("jpg");
            uploadInputVo.setFileName(file.getName());
            uploadInputVo.setFileSource("com_attachment_management");
            uploadInputVo.setFileVersion("0");
            comAttachmentFileService.storeFileToOss(file,uploadInputVo);
            log.info("GPS安装图片成功");
            FileUtil.del(file);
        }catch (Exception e){
            log.warn("{}GPS安装图片下载失败",id);
        }
    }

}
